package cn.ac.iie.ban.data.exchange.runner.tokenBucket.util;

import cn.ac.iie.ban.data.exchange.runner.tokenBucket.exception.DEFCRuntimeEnvException;
import cn.ac.iie.di.commons.speeder.limiter.TokenBucket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.builder.fluent.Configurations;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.ex.ConversionException;

public class RuntimeEnv {

    private static final String CONFIG_FILE_NAME = "configure.properties";

    public static final String SERVER_PORT = "server.port";
    public static final String SERVER_PARALLEL_SIZE = "server.parallel_size";
    public static final String SERVER_IP = "server.ip";

    public static final String META_URL = "meta.url";
    public static final String META_SUFFIX = "meta.suffix";
    public static final String META_UPDATE_INTERVAL = "meta.update.interval";

    public static final String LIMIT_TOTAL_PER_SEC = "limit.total.per.sec";
    public static final String LIMIT_SPEED = "limit.speed";
    public static final String LIMIT_SPEED_INTERVAL_SEC = "limit.speed.interval.sec";
    public static final String LIMIT_SIZE = "limit.size";
    public static final String LIMIT_SIZE_INTERVAL_SEC = "limit.size.interval.sec";
    public static final String LIMIT_SPEED_SPECIFIC_PRIFIX = "limit.speed.specific";

    public static final String STATISTIC_RMQ_NAMESRV = "statistic.rmq.namesrv";
    public static final String STATISTIC_RMQ_TOPIC = "statistic.rmq.topic";
    public static final String STATISTIC_INTERVAL_SEC = "statistic.interval.sec";

    private static Configuration conf = null;
    public static HashMap<String, Object> dynamicParams = new HashMap<>();

    public static Map<String, TokenBucket> bucketMap;

    public static void init() throws DEFCRuntimeEnvException {
        Configurations configs = new Configurations();
        try {
            conf = configs.properties(ClassLoader.getSystemClassLoader().getResource(CONFIG_FILE_NAME).getFile());
        } catch (ConfigurationException ex) {
            throw new DEFCRuntimeEnvException("load config file err.", ex);
        }
        bucketMap = new HashMap<>();

        getParamAsInteger(SERVER_PORT);
        getParamAsInteger(SERVER_PARALLEL_SIZE);
        getParamAsString(SERVER_IP);

        getParamAsStrings(META_URL);
        getParamAsString(META_SUFFIX);
        getParamAsInteger(META_UPDATE_INTERVAL);

        getParamAsInteger(LIMIT_TOTAL_PER_SEC);
        getParamAsInteger(LIMIT_SPEED, null);
        getParamAsInteger(LIMIT_SPEED_INTERVAL_SEC, 1);
        getParamAsInteger(LIMIT_SIZE, null);
        getParamAsInteger(LIMIT_SIZE_INTERVAL_SEC, 1);
        getAllParamAsInteger(LIMIT_SPEED_SPECIFIC_PRIFIX);

        getParamAsString(STATISTIC_RMQ_NAMESRV);
        getParamAsString(STATISTIC_RMQ_TOPIC);
        getParamAsInteger(STATISTIC_INTERVAL_SEC, 0);
    }

    public static String getParamAsString(String param) throws DEFCRuntimeEnvException {
        if (conf == null) {
            throw new DEFCRuntimeEnvException("conf not inited. Please call RuntimeEnv.init() first!");
        }
        String val;
        if (!dynamicParams.containsKey(param)) {
            val = conf.getString(param, null);
            if (val == null) {
                throw new DEFCRuntimeEnvException("param " + param + " not set!");
            }
            dynamicParams.put(param, val);
        } else {
            val = (String) dynamicParams.get(param);
        }
        return val;
    }

    public static String getParamAsString(String param, String Default) throws DEFCRuntimeEnvException {
        if (conf == null) {
            throw new DEFCRuntimeEnvException("conf not inited. Please call RuntimeEnv.init() first!");
        }
        String val = (String) dynamicParams.get(param);
        if (!dynamicParams.containsKey(param)) {
            val = conf.getString(param, Default);
            dynamicParams.put(param, val);
        }
        return val;
    }

    public static List<String> getParamAsStrings(String param) throws DEFCRuntimeEnvException {
        if (conf == null) {
            throw new DEFCRuntimeEnvException("conf not inited. Please call RuntimeEnv.init() first!");
        }
        List<String> val = (List<String>) dynamicParams.get(param);
        if (!dynamicParams.containsKey(param)) {
            val = conf.getList(String.class, param, null);
            if (val == null) {
                throw new DEFCRuntimeEnvException("param " + param + " not set!");
            }
            dynamicParams.put(param, val);
        }
        return val;
    }

    public static List<String> getParamAsStrings(String param, List<String> Default) throws DEFCRuntimeEnvException {
        if (conf == null) {
            throw new DEFCRuntimeEnvException("conf not inited. Please call RuntimeEnv.init() first!");
        }
        List<String> val = (List<String>) dynamicParams.get(param);
        if (!dynamicParams.containsKey(param)) {
            val = conf.getList(String.class, param, Default);
            dynamicParams.put(param, val);
        }
        return val;
    }

    public static Integer getParamAsInteger(String param) throws DEFCRuntimeEnvException {
        Integer val = (Integer) dynamicParams.get(param);
        if (!dynamicParams.containsKey(param)) {
            try {
                val = conf.getInt(param, -1);
            } catch (ConversionException ex) {
                throw new DEFCRuntimeEnvException("get runtime env error with integer value! param = " + param, ex);
            }
            if (val == -1) {
                throw new DEFCRuntimeEnvException("param " + param + " not set!");
            }
            dynamicParams.put(param, val);
        }
        return val;
    }

    public static Integer getParamAsInteger(String param, Integer Default) throws DEFCRuntimeEnvException {
        Integer val = (Integer) dynamicParams.get(param);
        if (!dynamicParams.containsKey(param)) {
            try {
                val = conf.getInteger(param, Default);
            } catch (ConversionException ex) {
                throw new DEFCRuntimeEnvException("get runtime env error with integer value! param = " + param, ex);
            }
            dynamicParams.put(param, val);
        }
        return val;
    }

    public static Boolean getParamAsBoolean(String param) throws DEFCRuntimeEnvException {
        Boolean val = (Boolean) dynamicParams.get(param);
        if (!dynamicParams.containsKey(param)) {
            try {
                if (conf.containsKey(param)) {
                    val = conf.getBoolean(param);
                } else {
                    throw new DEFCRuntimeEnvException("param " + param + " not set!");
                }
            } catch (ConversionException ex) {
                throw new DEFCRuntimeEnvException("get runtime env error with boolean value! param = " + param, ex);
            }
            dynamicParams.put(param, val);
        }
        return val;
    }

    public static Boolean getParamAsBoolean(String param, Boolean Default) throws DEFCRuntimeEnvException {
        Boolean val = (Boolean) dynamicParams.get(param);
        if (!dynamicParams.containsKey(param)) {
            try {
                val = conf.getBoolean(param, Default);
            } catch (ConversionException ex) {
                throw new DEFCRuntimeEnvException("get runtime env error with boolean value! param = " + param, ex);
            }
            dynamicParams.put(param, val);
        }
        return val;
    }

    public static HashMap<String, Integer> getAllParamAsInteger(String prefix) throws DEFCRuntimeEnvException {
        if (dynamicParams.containsKey(prefix)) {
            return (HashMap<String, Integer>) dynamicParams.get(prefix);
        } else {
            HashMap<String, Integer> val = new HashMap<>();
            Iterator<String> itr = conf.getKeys(prefix);
            while (itr != null && itr.hasNext()) {
                String key = itr.next();
                try {
                    Integer value = conf.getInt(key);
                    val.put(key, value);
                } catch (ConversionException ex) {
                    throw new DEFCRuntimeEnvException("get runtime env error with integer value! key = " + key, ex);
                }
            }
            dynamicParams.put(prefix, val);
            return val;
        }
    }

    public static HashMap<String, Integer> getAllParamAsInteger(String prefix, HashMap<String, Integer> Default) throws DEFCRuntimeEnvException {
        if (dynamicParams.containsKey(prefix)) {
            return (HashMap<String, Integer>) dynamicParams.get(prefix);
        } else {
            HashMap<String, Integer> val = new HashMap<>();
            Iterator<String> itr = conf.getKeys(prefix);
            while (itr != null && itr.hasNext()) {
                String key = itr.next();
                try {
                    Integer value = conf.getInt(key);
                    val.put(key, value);
                } catch (ConversionException ex) {
                    throw new DEFCRuntimeEnvException("get runtime env error with integer value! key = " + key, ex);
                }
            }
            if (val.isEmpty()) {
                dynamicParams.put(prefix, Default);
            } else {
                dynamicParams.put(prefix, val);
            }
            return val;
        }
    }
}
